package ascon_helper

// import "fmt"

const reg_size int = 64
var ASCON_128_IV []uint8 = []uint8{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}

func select_bit_bytes(i int, arr []uint8) uint8 {
	i = i % (len(arr)*8)
	re := (arr[i/8]>>(7-(i%8)))&1
	return re
}

func Select_subkey_sbox(i int, key []uint8) uint8{
	// if i<reg_size{
	sub_key := select_bit_bytes(i%reg_size, key[0:8])
	return sub_key
	// }
	//  else {
	// 	sub_key := select_bit_bytes(i%reg_size, key[0:8])^select_bit_bytes(i%reg_size, key[8:16])
	// 	return sub_key
	// }
}
type Parameter struct {
	Sub_key int
	Nonce0,Nonce1 []uint8
}
func Sbox_outout(bit_kg uint8,paras Parameter) uint8 {
	// if paras.Sub_key < reg_size {
	y4_i := func (x0,x1,x3,x4 uint8) uint8 {
		return x1&(x4^x0^1)^x3^x4
	}
	res := y4_i(select_bit_bytes(paras.Sub_key%reg_size,ASCON_128_IV),bit_kg,select_bit_bytes(paras.Sub_key%reg_size,paras.Nonce0),select_bit_bytes(paras.Sub_key%reg_size,paras.Nonce1))
	return res
	// }
	// else{
	// 	y2_i := func (x0,x12,x3,x4 uint8) uint8 {
	// 		return x4&(x3^1)^x12^1
	// 	}
	// 	res := y2_i(select_bit_bytes(paras.Sub_key%reg_size,ASCON_128_IV),bit_kg,select_bit_bytes(paras.Sub_key%reg_size,paras.Nonce0),select_bit_bytes(paras.Sub_key%reg_size,paras.Nonce1))
	// 	return res
	// }
}
//计算S盒输出比特
func Computer_Sbox_labels(keys []uint8, nonce0s, nonce1s [][]uint8, n_bit int) [][]uint8{
	num_labels := len(nonce0s)
	// fmt.Println(num_labels)
	var label_y [][]uint8
	for i:=0;i<num_labels;i++{
		var tmp[]uint8
		// fmt.Println(tmp)
		for j:=0;j<n_bit;j++{
			trace_paras := Parameter{Sub_key:j,Nonce0:nonce0s[i],Nonce1:nonce1s[i]}
			// fmt.Println(trace_paras)
			// fmt.Println(keys)
			key_guess:=Select_subkey_sbox(trace_paras.Sub_key,keys)
			t := Sbox_outout(key_guess,trace_paras)
			tmp = append(tmp,t)
			
		}
		// fmt.Println(tmp)
		// fmt.Println(len(tmp))
		label_y = append(label_y,tmp)
	}
	return label_y
}
//计算汉明重量
func Hw_weights(labels [][]uint8) []uint8{
	lenss := len(labels)
	item := len(labels[0])
	out  := make([]uint8,0)
	for i:=0;i<lenss;i++{
		var tmp uint8
		for j:=0;j<item;j++{
			if labels[i][j]==1{
				tmp+=1
			}
		}
		out = append(out,tmp)
	}
	return out
}

func HW_2c(labels [][]uint8) []uint8{
	tmp := Hw_weights(labels)
	var out []uint8
	for _,e:= range tmp{
		if e>=32{
			out = append(out,uint8(1))
		}else{
			out = append(out,uint8(0))
		}
	}
	return out
}